#pragma once
#include <CGAL/Cartesian.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Partition_traits_2.h>
#include <CGAL/partition_2.h>
class ZMPointInfo
{
public:
	//typedef ZMVector<ZMReal>::const_iterator Cartesian_const_iterator;
	typedef const ZMReal* Cartesian_const_iterator;
	ZMPointInfo() :m_iIndex(-1)
	{
	//	m_v.resize(3);
		m_v[0] = m_v[1] = m_v[2] = 0;
	}

	ZMPointInfo(const ZMReal x, const ZMReal y, int c = -1)
		:m_iIndex(c)
	{
		//m_v.resize(3);
		m_v[0] = x;
		m_v[1] = y;

	}

	ZMPointInfo(const ZMReal x, const ZMReal y, const ZMReal z, int c = -1)
		:m_iIndex(c)
	{
	//	m_v.resize(3);
		m_v[0] = x;
		m_v[1] = y;
		m_v[2] = z;

	}

	Cartesian_const_iterator cartesian_begin() const
	{
		return zm_cartesian_begin();
	}
	int dimension() const
	{
		return std::distance(zm_cartesian_end(), zm_cartesian_begin());
	}
	virtual  Cartesian_const_iterator zm_cartesian_begin() const
	{
		return m_v;
	}
	virtual Cartesian_const_iterator zm_cartesian_end() const
	{
		return m_v + 3;
	}
	Cartesian_const_iterator cartesian_end() const
	{
		return zm_cartesian_end();
	}
	const int& Index() const { return m_iIndex; }

	int& Index() { return m_iIndex; }

	const ZMReal& x() const  { return m_v[0]; }

	const ZMReal& y() const { return m_v[1]; }

	const ZMReal& z() const { return m_v[2]; }

	ZMReal & x() { return m_v[0]; }

	ZMReal& y() { return m_v[1]; }

	ZMReal& z() { return m_v[2]; }

	const ZMReal & hx() const
	{
		return x();
	}
	const ZMReal & hy() const
	{
		return y();
	}
	const ZMReal & hz() const
	{
		return z();
	}
	virtual bool operator==(const ZMPointInfo &p) const
	{
		return (x() == p.x() && y() == p.y() && z() == p.z() && (m_iIndex == p.m_iIndex));
	}

	bool operator!=(const ZMPointInfo &p) const
	{
		return !(*this == p);
	}

	ZMPointInfo operator+(const ZMPointInfo &p) const
	{
		return ZMPointInfo(x() + p.x(), y() + p.y(), z() + p.z());
	}
	ZMPointInfo operator-(const ZMPointInfo &p) const
	{
		return ZMPointInfo(x() - p.x(), y() - p.y(), z() - p.z());
	}
	ZMPointInfo operator*(const float &p) const
	{
		return ZMPointInfo(x() * p, y() * p, z() * p);
	}
protected:
	ZMReal m_v[3];
	int m_iIndex;
};

class ZMPointInfo2 :public ZMPointInfo
{
public:
	ZMPointInfo2() :ZMPointInfo()
	{
	}

	ZMPointInfo2(const ZMReal x, const ZMReal y, int c = -1) :ZMPointInfo(x, y, c)
	{

	}
	virtual  Cartesian_const_iterator zm_cartesian_begin() const
	{
		return m_v;
	}
	virtual Cartesian_const_iterator zm_cartesian_end() const
	{
		return m_v + 2;;
	}


	virtual bool operator==(const ZMPointInfo &p) const
	{
		return (x() == p.x() && y() == p.y() && (m_iIndex == p.Index()));
	}

};
typedef ZMPointInfo ZMPointInfo3;

template <typename K, typename OldK>
class ZMConstruct_pointInfo_2
{
	typedef typename K::RT         RT;
	typedef typename K::Point_2    Point_2;
	typedef typename K::Line_2     Line_2;
	typedef typename Point_2::Rep  Rep;
public:
	typedef Point_2                result_type;
	// Note : the CGAL::Return_base_tag is really internal CGAL stuff.
	// Unfortunately it is needed for optimizing away copy-constructions,
	// due to current lack of delegating constructors in the C++ standard.
	// Point_2
	Rep operator()(CGAL::Return_base_tag, CGAL::Origin o) const
	{
		return Rep(o);
	}
	// Point_2
	Rep operator()(CGAL::Return_base_tag, const RT& x, const RT& y) const
	{
		return Rep(x, y);
	}
	Rep operator()(CGAL::Return_base_tag, const RT& x, const RT& y, const RT& w) const
	{
		BOOST_ASSERT(false);
		if (w != 0)
		{
			return Rep(x / w, y / w);
		}
		return Rep(x, y);
	}
	Point_2	operator()(const CGAL::Origin&) const
	{
		return ZMPointInfo2(0, 0);
	}
	Point_2	operator()(const RT& x, const RT& y) const
	{
		return ZMPointInfo2(x, y);
	}
	Point_2	operator()(const RT& x, const RT& y, const RT& w) const
	{
		BOOST_ASSERT(false);
		if (w != 0)
		{
			return ZMPointInfo2(x / w, y / w);
		}
		return ZMPointInfo2(x, y);
	}

	Point_2	operator()(const Line_2& l) const
	{
		typename OldK::Construct_point_2 base_operator;
		Point_2 p = base_operator(l);
		return p;
	}
	Point_2	operator()(const Line_2& l, int i) const
	{
		typename OldK::Construct_point_2 base_operator;
		return base_operator(l, i);
	}
};


template <typename K, typename OldK>
class ZMConstruct_pointInfo_3
{
	typedef typename K::RT         RT;
	typedef typename K::Point_3    Point_3;
	typedef typename K::Line_3     Line_3;
	typedef typename Point_3::Rep  Rep;
public:
	typedef Point_3                result_type;
	// Note : the CGAL::Return_base_tag is really internal CGAL stuff.
	// Unfortunately it is needed for optimizing away copy-constructions,
	// due to current lack of delegating constructors in the C++ standard.
	// Point_2
	Rep operator()(CGAL::Return_base_tag, CGAL::Origin o) const
	{
		return Rep(o);
	}
	// Point_3
	Rep operator()(CGAL::Return_base_tag, const RT& x, const RT& y, const RT& z) const
	{
		return Rep(x, y, z);
	}
	Rep operator()(CGAL::Return_base_tag, const RT& x, const RT& y, const RT& z, const RT& w) const
	{
		if (w != 0)
		{
			return Rep(x / w, y / w, z / w);
		}
		return Rep(x, y, z);
	}
	Point_3	operator()(const CGAL::Origin&) const
	{
		return ZMPointInfo3(0, 0, 0);
	}
	Point_3	operator()(const RT& x, const RT& y, const RT& z) const
	{
		return ZMPointInfo3(x, y, z);
	}
	Point_3	operator()(const RT& x, const RT& y, const RT& z, const RT& w) const
	{
		BOOST_ASSERT(false);
		if (w != 0)
		{
			return ZMPointInfo3(x / w, y / w, z / w);
		}
		return ZMPointInfo3(x, y, z);
	}
	Point_3	operator()(const Line_3& l) const
	{
		typename OldK::Construct_point_3 base_operator;
		Point_3 p = base_operator(l);
		return p;
	}
	Point_3	operator()(const Line_3& l, int i) const
	{
		typename OldK::Construct_point_3 base_operator;
		return base_operator(l, i);
	}
};

template <typename K>
class ZMConstruct_cartesian_const_iterator_3
{
	typedef typename K::Point_3          Point_3;
	typedef typename K::Vector_3         Vector_3;
	typedef typename K::Cartesian_const_iterator_3
		Cartesian_const_iterator_3;

public:
	typedef Cartesian_const_iterator_3 result_type;

	Cartesian_const_iterator_3
		operator()(const Point_3& p) const
	{
		return p.zm_cartesian_begin();
	}

	Cartesian_const_iterator_3
		operator()(const Point_3& p, int) const
	{
		return p.zm_cartesian_end();
	}

	Cartesian_const_iterator_3
		operator()(const Vector_3& v) const
	{
		return v.rep().cartesian_begin();
	}

	Cartesian_const_iterator_3
		operator()(const Vector_3& v, int) const
	{
		return v.rep().cartesian_end();
	}
};

// K_ is the new kernel, and K_Base is the old kernel
template < typename K_, typename K_Base>
class ZMCartesian_base_PointWithInfo : public K_Base::template Base<K_>::Type
{
	typedef typename K_Base::template Base<K_>::Type   OldK;
public:
	typedef K_										Kernel;
	typedef ZMPointInfo2							Point_2;
	typedef ZMPointInfo3							Point_3;
	typedef ZMConstruct_pointInfo_2<Kernel, OldK>       Construct_point_2;
	typedef ZMConstruct_pointInfo_3<Kernel, OldK>       Construct_point_3;
	typedef ZMConstruct_cartesian_const_iterator_3<Kernel>       Construct_cartesian_const_iterator_3;
	
	typedef typename const K_Base::FT*				Cartesian_const_iterator_2;
	typedef typename const K_Base::FT*				Cartesian_const_iterator_3;

	template < typename Kernel2 >
	struct Base { typedef ZMCartesian_base_PointWithInfo<Kernel2, K_Base>  Type; };


	Construct_point_3	construct_point_3_object() const
	{
		return Construct_point_3();
	}
	Construct_point_2	construct_point_2_object() const
	{
		return Construct_point_2();
	}
};

template < typename FT_ >
class ZMKernelWithPointInfo :
	public CGAL::Type_equality_wrapper<	ZMCartesian_base_PointWithInfo<ZMKernelWithPointInfo<FT_>, CGAL::Cartesian<FT_> >, ZMKernelWithPointInfo<FT_> >
{
};

typedef ZMKernelWithPointInfo<ZMReal>                   MKCGALWithInfo;
typedef CGAL::Filtered_kernel_adaptor<MKCGALWithInfo>	KCGALWithInfo;

namespace CGAL {
	extern MKCGALWithInfo::Point_3	projection_plane(const MKCGALWithInfo::Point_3 &p, const MKCGALWithInfo::Plane_3 &h);
} //namespace CGAL

typedef KCGALWithInfo K;
typedef K::Point_3 CGALPoint;
typedef K::Point_2 CGALPoint2;
typedef K::Vector_3 CGALVector;
typedef K::Vector_2 CGALVector2;
typedef K::Line_3 CGALLine;
typedef K::Segment_3 CGALSegment;
typedef K::Segment_2 CGALSegment2;
typedef CGAL::Partition_traits_2<K>     Traits;
typedef Traits::Polygon_2 CGALPolygon2;
typedef K::Triangle_3 CGALTriangle;
typedef K::Triangle_2 CGALTriangle2;

#include <CGAL/AABB_tree.h>
#include <CGAL/AABB_traits.h>
#include <CGAL/AABB_triangle_primitive.h>
#include <CGAL/AABB_segment_primitive.h>
#include "Vector3d.h"

#ifdef USE_SELF_DEF
class ZMLine :public CGALLine
{
	typedef K::Point_3 Point;
	typedef K::Vector_3 Vector;
public:
	ZMLine(const ZMPoint3D& pFrom, const ZMPoint3D& pTo) :
		CGALLine(Point(pFrom[0], pFrom[1], pFrom[2]), Point(pTo[0], pTo[1], pTo[2]))
	{
	}
};

class ZMSegmengt :public CGALSegment
{
	typedef K::Point_3 Point;
public:
	ZMSegmengt(const ZMPoint3D& pFrom, const ZMPoint3D& pTo) :
		CGALSegment(Point(pFrom[0], pFrom[1], pFrom[2]), Point(pTo[0], pTo[1], pTo[2]))
	{

	}
	ZMSegmengt(const Point& pFrom, const Point& pTo) :
		CGALSegment(pFrom, pTo)
	{

	}
	ZMSegmengt(const CGALSegment& seg) :
		CGALSegment(seg)
	{

	}
	bool HasOn(const ZMPoint3D& pnt)
	{
		return this->has_on(Point(pnt[0], pnt[1], pnt[2]));
	}
};

class ZMTriangle :public CGALTriangle
{
	typedef K::Point_3 Point;
public:
	ZMTriangle(const ZMPoint3D& p1, const ZMPoint3D& p2, const ZMPoint3D& p3) :
		CGALTriangle(Point(p1[0], p1[1], p1[2]), Point(p2[0], p2[1], p2[2]), Point(p3[0], p3[1], p3[2]))
	{

	}
};

#else
typedef CGALLine ZMLine;
typedef CGALSegment ZMSegmengt;
typedef CGALSegment2 ZMSegmengt2;
typedef CGALTriangle ZMTriangle;
typedef CGALTriangle2 ZMTriangle2;
typedef CGALPolygon2 ZMPolygon2;

#endif



typedef ZMVector<ZMTriangle>::const_iterator IteratorTri;
typedef CGAL::AABB_triangle_primitive<K, IteratorTri> PrimitiveTri;
typedef CGAL::AABB_traits<K, PrimitiveTri> AABB_triangle_traits;
typedef CGAL::AABB_tree<AABB_triangle_traits> TreeTri;
typedef std::shared_ptr<TreeTri> PTreeTri;

typedef ZMVector<ZMSegmengt>::const_iterator IteratorSeg;
typedef CGAL::AABB_segment_primitive<K, IteratorSeg> PrimitiveSegment;
typedef CGAL::AABB_traits<K, PrimitiveSegment> AABB_segment_traits;
typedef CGAL::AABB_tree<AABB_segment_traits> TreeSeg;
typedef std::shared_ptr<TreeSeg> PTreeSeg;


